package org.budo.netty.servlet.server.connector.netty;

import org.budo.netty.servlet.server.connector.AbstractHttpConnector;
import org.budo.netty.servlet.server.handler.BudoServletHandler;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import lombok.extern.slf4j.Slf4j;

/**
 * @author lmw
 */
@Slf4j
public class NettyHttpConnector extends AbstractHttpConnector {
    private static final int MAX_CONTENT_LENGTH = 65536;

    public NettyHttpConnector(Integer port) {
        this.setPort(port);
    }

    @Override
    public void start(BudoServletHandler servletHandler) {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            this.startNetty(bossGroup, workerGroup, servletHandler);
        } catch (Throwable e) {
            log.error("#31 startNetty error", e);
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    private void startNetty(EventLoopGroup bossGroup, EventLoopGroup workerGroup, final BudoServletHandler servletHandler) throws InterruptedException {
        ServerBootstrap serverBootstrap = new ServerBootstrap();

        serverBootstrap.group(bossGroup, workerGroup) //
                .channel(NioServerSocketChannel.class) //
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline().addLast("http-decoder", new HttpRequestDecoder()) //
                                .addLast("http-aggregator", new HttpObjectAggregator(MAX_CONTENT_LENGTH)) // 将多个消息转换为单一的FullHttpRequest或FullHttpResponse对象
                                .addLast("http-encoder", new HttpResponseEncoder()) //
                                .addLast("servlet-handler", new NettyServletHandlerWrapper(servletHandler)); //
                    }
                });

        ChannelFuture channelFuture = serverBootstrap.bind(this.getPort()).sync();

        log.info("#59 Servlet Server startup. on port " + this.getPort() + ", this=" + this);
        channelFuture.channel().closeFuture().sync();
    }
}